//; ---------------------------------------------------------------------------
//; Object 1A - GHZ collapsing ledge
//; ---------------------------------------------------------------------------

#include "ledge.h"

#include "../sprite.h"
#include "../objectsystemNEWER.h"
#include "../collision.h"

static object *obj;

//EXTERN DEFINITIONS HERE

//; ---------------------------------------------------------------------------
//; Sprite mappings - (OBJECT)
//; ---------------------------------------------------------------------------

//==========

void (*Ledge_Index[6])() = { Ledge_Main, Ledge_Touch, Ledge_Collapse, Ledge_Display, Ledge_Delete, Ledge_WalkOff };

//OBJECT:					; XREF: Obj_Index
void CollapseLedge(object *_obj)
{
    obj = _obj;

    //moveq	#0,d0
    //move.b	obRoutine(a0),d0
    byte routine = obj->Routine/2;

    //move.w	Ring_Index(pc,d0.w),d1
    //jmp	Ring_Index(pc,d1.w)
    (*Ledge_Index[routine])();
}

//; ===========================================================================

#define timedelay 0x38    //; time between touching the ledge and it collapsing
#define collapse  0x3A	  //; collapse flag

//Ledge_Main:	; Routine 0
void Ledge_Main()
{
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;
	
    //move.l	#Map_Ledge,obMap(a0)
    obj->Map = Map_Ledge;
	
    //move.w	#$4000,obGfx(a0)
    obj->Gfx = 0x4000;

    //ori.b	#4,obRender(a0)
    obj->Render = obj->Render | 4;

    //move.b	#4,obPriority(a0)
    obj->Priority = 4;

    //move.b	#7,timedelay(a0) ; set time delay for collapse
    obj->Variables[timedelay-0x28] = 7;
	
    //move.b	#$64,obActWid(a0)
    obj->ActionWidth = 0x64;

    //move.b	obSubtype(a0),obFrame(a0)
    obj->Frame = obj->Subtype;

    //move.b	#$38,obHeight(a0)
    obj->Height = 0x38;

    //bset	#4,obRender(a0)
    obj->Render = obj->Render | 16;
}

void Ledge_Touch()	//; Routine 2
{
    //tst.b	collapse(a0)	; is ledge collapsing?
    //beq.s	@slope		; if not, branch
    if (obj->Variables[collapse-0x28] != 0)
    {
        //tst.b	timedelay(a0)	; has time reached zero?
        //beq.w	Ledge_Fragment	; if yes, branch
        if (obj->Variables[timedelay-0x28] == 0) { Ledge_Fragment(); return;}
        else
        {
	    //subq.b	#1,timedelay(a0) ; subtract 1 from time
            obj->Variables[timedelay-0x28] = obj->Variables[timedelay-0x28] - 1;
        }
    }
           
    //@slope:
    //move.w	#$30,d1
    word slopeWidth = 48;  //some x-distance to slope object

    //lea	(Ledge_SlopeData).l,a2
    byte *slopeData = Ledge_SlopeData;

    //bsr.w	SlopeObject
    SlopeObject(obj, slopeWidth, slopeData);
 
    //bra.w	RememberState
    RememberState(obj);

    //; ===========================================================================
}

//; ===========================================================================
//; ===========================================================================



//Ledge_Collapse:	; Routine 4
void Ledge_Collapse()
{
    //tst.b	timedelay(a0)
    if (obj->Variables[timedelay-0x28] == 0)
    {
        //beq.w	loc_847A          //PART OF LEDGE_FRAGMENT IN COLLISION
        loc_847A(obj);
    }
    else
    {
        //move.b	#1,collapse(a0)	; set collapse flag
        obj->Variables[collapse-0x28] = 1;
	
	//subq.b	#1,timedelay(a0)
        obj->Variables[timedelay-0x28] = obj->Variables[timedelay-0x28] - 1;
        
        Ledge_WalkOff();
    }
}

//; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||


//Ledge_WalkOff:	; Routine $A
void Ledge_WalkOff()
{
    //move.w	#$30,d1
    word ledgeWidth = 48;

    signed short distPlayerLedge;
    //bsr.w	ExitPlatform
    ExitPlatform(obj, ledgeWidth, distPlayerLedge);
		
    //move.w	#$30,d1
    word slopeWidth = 48;

    //lea	(Ledge_SlopeData).l,a2
    byte *slopeData = Ledge_SlopeData;

    //move.w	obX(a0),d2
    word slopeX = obj->X;

    //bsr.w	SlopeObject2
    SlopeObject2(obj, slopeWidth, slopeX, slopeData);

    //bra.w	RememberState
    RememberState(obj);

}   //; End of function Ledge_WalkOff

; ===========================================================================

//Ledge_Display:	; Routine 6
void Ledge_Display()
{
    //tst.b	timedelay(a0)	; has time delay reached zero?
    //beq.s	Ledge_TimeZero	; if yes, branch
    if (obj->Variables[timedelay-0x28] == 0) { Ledge_TimeZero(); }
    else
    {
        //tst.b	collapse(a0)	; is ledge collapsing?
        //bne.w	loc_82D0	; if yes, branch
        if (obj->Variables[collapse-0x28] == 0)
        {
	    //subq.b	#1,timedelay(a0) ; subtract 1 from time
            obj->Variables[timedelay-0x28] = obj->Variables[timedelay-0x28] - 1;

	    //bra.w	DisplaySprite
            DisplaySprite(obj);
        }   //; ===========================================================================
        else
        {
            //loc_82D0:
	    //subq.b	#1,timedelay(a0)
            obj->Variables[timedelay-0x28] = obj->Variables[timedelay-0x28] - 1;

            //bsr.w	Ledge_WalkOff
            Ledge_WalkOff();

	    //lea	(v_player).w,a1
	    //btst	#3,obStatus(a1)
            //beq.s	loc_82FC
            if ((player.Status & 8) == 8)
            {
                //tst.b	timedelay(a0)
		//bne.s	locret_8308
		if (obj->Variables[timedelay-0x28] != 0) { return; }
                
                //bclr	#3,obStatus(a1)
                player.Status = player.Status - (player.Status & 8);

		//bclr	#5,obStatus(a1)
                player.Status = player.Status - (player.Status & 32);

		//move.b	#1,obNextAni(a1)
                player.NextAni = 1;
            }

            //loc_82FC:
	    //move.b	#0,collapse(a0)
            obj->Variables[collapse-0x28] = 0;

	    //move.b	#6,obRoutine(a0) ; run "Ledge_Display" routine
            obj->Routine = 6;

            //locret_8308:
	    //rts
        }
    }
}	

//; ===========================================================================

//Ledge_TimeZero:
void Ledge_TimeZero()
{
    //bsr.w	ObjectFall
    ObjectFall();

    //bsr.w	DisplaySprite
    DisplaySprite(obj);

    //tst.b	obRender(a0)
    //bpl.s	Ledge_Delete
    if (obj->Render < 0x80) { Ledge_Delete(); }
		
}   //rts	

//; ===========================================================================

//Ledge_Delete:	; Routine 8
void Ledge_Delete()
{
    //bsr.w	DeleteObject
    DeleteObject(obj);

}   //rts	



//===============================
//#define timedelay 0x38
//#define collapse 0x3A

//Ledge_Fragment:				; XREF: Obj1A_ChkTouch
void Ledge_Fragment(object *obj)
{
    //move.b	#0,collapse(a0)
    obj->Variables[collapse - 0x28] = 0;

    loc_847A(obj);
}

//loc_847A:				; XREF: Obj1A_Touch
void loc_847A(object *obj)
{
    //lea	(CFlo_Data1).l,a4
    byte *fragData = CFlo_Data1;

    //moveq	#$18,d1
    long numFragments = 24;

    //addq.b	#2,obFrame(a0)
    obj->Frame = obj->Frame + 2;

    //loc_8486:				; XREF: CFlo_Fragment
    //moveq	#0,d0
    //move.b	obFrame(a0),d0
    byte obFrame = obj->Frame;

    //add.w	d0,d0
    word mapOffset = obFrame * 2;

    
    //movea.l	obMap(a0),a3
    //adda.w	(a3,d0.w),a3
    byte *mapForFrame = obj->Map[mapOffset];

    //addq.w	#1,a3
    mapForFrame = mapForFrame + 1;     //skip mappings count

    #define currentBlock mapForFrame
    //from here on we change both the parent object and spawn additional objects to serve as children 
    //each child object/(fragment)'s mappings now points to a PORTION of the original object's mappings (a.k.a ONE block/five byte entry)
    
    //this means the RAW MAPPINGS flag has to be set, otherwise buildsprites will look for sub-mappings/multiple entrys when we only need a SINGLE entry
    //bset	#5,obRender(a0)
    obj->Render = obj->Render | 32;    

    //move.b	0(a0),d4
    byte parentID = obj->ID;

    //move.b	obRender(a0),d5
    byte parentRenderRaw = obj->Render;

    //movea.l	a0,a1
    object *childObj = obj;      //first child object will take place of the parent...

    //bra.s	loc_84B2
    //; ===========================================================================


    while (true)
    {
        //loc_84B2:
	//move.b	#6,obRoutine(a1)
        childObj->Routine = 6;

	//move.b	d4,0(a1)
        childObj->ID = parentID;

	//move.l	a3,obMap(a1)
        childObj->Map = (byte**)currentBlock;

	//move.b	d5,obRender(a1)
        childObj->Render = parentRenderRaw;

	//move.w	obX(a0),obX(a1)
        childObj->X = obj->X;

	//move.w	obY(a0),obY(a1)
        childObj->Y = obj->Y;

	//move.w	obGfx(a0),obGfx(a1)
        childObj->Gfx = obj->Gfx;
	
	//move.b	obPriority(a0),obPriority(a1)
        childObj->Priority = obj->Priority;
	
	//move.b	obActWid(a0),obActWid(a1)
        childObj->ActionWidth = obj->ActionWidth;
	
	//move.b	(a4)+,timedelay(a1)
        childObj->Variables[timedelay - 0x28] = *(fragData++);

	//cmpa.l	a0,a1
	//bhs.s	loc_84EE
        //bsr.w	DisplaySprite1
        if (childObj > obj) { DisplaySprite(childObj); }   //we don't need multiple displaysprite routines...
   
        //loc_84EE:
	//dbf	d1,loc_84AA
        if ((numFragments--) < 0) { break; }
         
        //loc_84AA:
	//bsr.w	FindFreeObj
        childObj = FindFreeObj();
 
	//bne.s	loc_84F2
        if (childObj != 0) { break; }
 
	//addq.w	#5,a3
        currentBlock = currentBlock + 5;     //next mappings block
    }

    //loc_84F2:
    //bsr.w	DisplaySprite
    DisplaySprite(obj);

    //sfx	sfx_Collapse,1	; play collapsing sound
}   

//; ===========================================================================
//; ---------------------------------------------------------------------------
//; Disintegration data for collapsing ledges (MZ, SLZ, SBZ)
//; ---------------------------------------------------------------------------
//CFlo_Data1:	
//		dc.b 
byte CFlo_Data1[26] = { 0x1C, 0x18, 0x14, 0x10, 0x1A, 0x16, 0x12,  0xE, 0xA, 6, 0x18, 0x14, 0x10, 0xC, 8, 4,
                        0x16, 0x12,  0xE,  0xA,    6,    2, 0x14, 0x10, 0xC, 0 };
byte CFlo_Data2[8] = {	0x1E, 0x16,  0xE,    6, 0x1A, 0x12,  0xA,    2 };
byte CFlo_Data3[8] = {	0x16, 0x1E, 0x1A, 0x12,    6,  0xE,  0xA,    2 };
